/*River Warren
 *October 7, 2011
 *
 *Room.cpp
 */

#include "Room.h"
#include "Utility.h"
#include <strings.h>
// Define directions in the array (this is way too hard codded in my opinion but so be it)
#define north 0
#define east 1
#define south 2
#define west 3



//constructor sets all values to null
Room::Room()
{
    setObjectType("Room");
    linkID = "null";
    NorthLink = "null";
    EastLink = "null";
    SouthLink = "null";
    WestLink = "null";
    linkArray[0] = NorthLink;
    linkArray[1] = EastLink;
    linkArray[2] = SouthLink;
    linkArray[3] = WestLink;
    //description = "null";
    N_desc = "null";
    E_desc = "null";
    S_desc = "null";
    W_desc = "null";
    descArray[4] = W_desc;
    descArray[3] = S_desc;
    descArray[2] = E_desc;
    descArray[1] = N_desc;
    //descArray[0] = description;
    has_door = false;
    
    // setup null direction objects;
    
    //Direction north("north");
    
    
    directions[north].setDirectionName("north");
    directions[south].setDirectionName("south");
    directions[east].setDirectionName("east");
    directions[west].setDirectionName("west");
}

//closing game (room object goes out of scope)
//will cause room state to be saved
Room::~Room()
{
}

//getLink to next room
//must be contained within try catch block
//paramaters:1=north,2=east,3=south,4=west
string Room::getLink(int direction)
{
    //direction must >=1 && <= 4
    if(direction >= 1 && direction <= 4)
    {
        //if direction link is not null
        if(linkArray[direction - 1].compare("null") != 0)
        {
            //check if direction is blocked by door
            //and if door is locked
            if(has_door == direction && d.isLocked())
            {
                //if locked door throw door description string
                string errorMsg = "Door is Locked " + d.getDesc();
                throw errorMsg;
            }
            //and enter new room
            return linkArray[direction - 1];
        }
        //if direction link is null (player may not move in that direction)
        //throw direction description string
        else throw descArray[direction];
    }
    //if !(1 <= direction <= 4) throw error msg
    string errorMsg = "That is not a valid direction";
    throw errorMsg;
}

//get description of room
string Room::getDesc()
{
    string out;//string to hold complete description
    //walk down array holding general and direction descriptions
    for(int i = 0; i < 5; ++i)
    {
        //if description is not null
        if(directions[i].getDesc().compare("null") != 0)
        {
            //add description part to out string
            out += directions[i].getDesc() + ' ';
            //if direction has a door
            if(i != 0 && i == has_door)
                //add description of door
                out += d.getDesc() + ' ';
        }
        //querry inventory for descriptions**********************************to be implemented
    }
    return out;
}


//must be put into try catch block
//	unlock door with proper key Id else throws exception
//	parameter: string with object Id of key
//	returns
//		paramater matches key code returns true
//		paramater does not matches key code returns false
bool Room::unlockDoor(string itemID)
{
    if(has_door == 0)
    {
        string errorMsg = "There is no door to unlock";
        throw errorMsg;
    }
    return d.unlock(itemID);
}

//writes new room state to file
void Room::saveRoom()
{
    //file name is Id and extention
    string fileName = linkID + ".grm";
    ofstream out(fileName.c_str());
    if(out.is_open())
    {
        out << linkID << ',' << has_door << ',' << NorthLink << ',' << EastLink << ',' << SouthLink << ',' << WestLink << endl
        << Base::getDesc() << endl << N_desc << endl << E_desc << endl << S_desc << endl << W_desc << endl
        << d << endl;
        
    }
    out.close();
}


//should be put into try catch block
//	if file does not exist (bad ID) throw bad ObjectID error
//	loads new room from file
//	parameter: ID of new room
void Room::loadRoom(string newID)
{
    char *tk = NULL;// pointers to chars
    char data[MAX] = ""; //to hold line
    string fileName;//string to hold file name
    
    
	fileName = "Data/" + newID + ".grm";//file name is room Id (obtained from this room link) and extention
	ifstream in(fileName.c_str());//opwn file
    if(in)
    {
        in.getline(data,MAX - 1, '\n'); //get line
        tk = strtok(data, DELIMS);  //get first token of new line
        linkID = tk;//first token is room Id
        objectID = tk; // set object ID
        tk = strtok(NULL, DELIMS);  //get token
        has_door = atoi(tk);//has door is int
        
        
        tk = strtok(NULL, DELIMS); // get next token
        
        string tmpString = tk;
        string needle = "R";
        tmpString.erase(tmpString.find_last_not_of(" \n\r\t")+1);
        if (tmpString.find_first_of(needle) != string::npos) {
            directions[north].setNextRoomID(tmpString);
        }
        
        
        tk = strtok(NULL, DELIMS); // get next token
        tmpString = tk;
        tmpString.erase(tmpString.find_last_not_of(" \n\r\t")+1);
        if (tmpString.find_first_of(needle) != string::npos) {
            
            directions[east].setNextRoomID(tmpString);
        }
        tk = strtok(NULL, DELIMS); // get next token
        
        tmpString = tk;
        tmpString.erase(tmpString.find_last_not_of(" \n\r\t")+1);
        if (tmpString.find_first_of(needle) != string::npos) {
            
            directions[south].setNextRoomID(tmpString);
        }
        
        tk = strtok(NULL, DELIMS); // get next token
        
        tmpString = tk;
        tmpString.erase(tmpString.find_last_not_of(" \n\r\t")+1);
        if (tmpString.find_first_of(needle) != string::npos) {
            
            directions[west].setNextRoomID(tmpString);
        }
        
        in.getline(data,MAX - 1, '\n'); //get line
        Base::setDesc(data);
        in.getline(data,MAX - 1, '\n'); //get line
        directions[north].setDesc(data);
        in.getline(data,MAX - 1, '\n'); //get line
        directions[east].setDesc(data);
        E_desc = data;
        in.getline(data,MAX - 1, '\n'); //get line
        directions[south].setDesc(data);
        S_desc = data;
        in.getline(data,MAX - 1, '\n'); //get line
        directions[west].setDesc(data);
        W_desc = data;
        //put links into link array
        linkArray[0] = NorthLink;
        linkArray[1] = EastLink;
        linkArray[2] = SouthLink;
        linkArray[3] = WestLink;
        //put descriptions into description array
        descArray[0] = Base::getDesc();
        descArray[1] = directions[north].getDesc();
        descArray[2] = directions[east].getDesc();;
        descArray[3] = directions[south].getDesc();
        descArray[4] = directions[west].getDesc();
        //get door object data
        in >> d;
    }
    else
    {
        string errorMsg = "Bad ObjectID error";
        //throw errorMsg;
    }
    in.close();
}

Direction * Room::getDirections() {
    
    Direction * dirPTR;
    
    dirPTR = directions;
    
    return dirPTR;
}

Direction Room::getDirection(std::string directionToGet) {
    
    if (directionToGet == "north") {
        return directions[north];
    }
    if (directionToGet == "east") {
        return directions[east];
    }
    if (directionToGet == "west") {
        return directions[west];
    }
    if (directionToGet == "south") {
        return directions[south];
    }
    else {
        Direction badDirection("bad direction");
        badDirection.setDesc("bad direction");
        return badDirection;
    }
    
}

//returns key code for opening door
//if there is a door to open
//otherwise returns empty string
string Room::getKeyCode()
{
    if(hasDoor()){return d.getKeyCode();}
    return "";
}

const string Room::getObjectID() {
    
    return objectID;
}
//********************************************************
// Overloaded == operator. Gives ability to "search" class  *
// *******************************************************

bool operator== (const Room &obj1, const string &objectID) {
    
    return (obj1.objectID == objectID);
}

//********************************************************
// Overloaded == operator. Gives ability to "search" class  *
// *******************************************************

bool operator== (const Room &obj1, const Room &obj2) {
    
    return (obj1.objectID == obj2.objectID);
}

